#include "ValueType.h"



ValueType::ValueType (Types type, int dimensions) {
	this->type = type;
	this->dimensionality = dimensions;
	setTypeName(type);
}

ValueType::ValueType (SyntaxTreeNode *variableTypeNode, int dimensions) {
	setType(variableTypeNode, dimensions);
}






/**
 *  @fn	ValueType::ValueType(int id)
 *
 *  @brief	Constructor.
 *
 *  @author	Nikola Novak
 *  @date	6/16/2009
 *
 *  @param	id	The identifier.
 */
ValueType::ValueType(int id) : id(id), constant(false), evaluated(false) { }
/**
 *  @fn	ValueType::ValueType(const ValueType &copy)
 *
 *  @brief	Constructor.
 *
 *  @author	Nikola Novak
 *  @date	9/22/2009
 *
 *  @param	copy	The copy.
 */
ValueType::ValueType(ValueType &copy) {
	id = copy.id;
	dimensionality = copy.dimensionality;
	for (std::vector<ValueType *>::iterator i = copy.myTemplate.begin(); i != copy.myTemplate.end(); ++i) {
		myTemplate.push_back(new ValueType(*(*i)));
	}
	dimensions = copy.dimensions;
	evaluated = copy.evaluated;
	type = copy.type;
	typeName = copy.typeName;
	constant = copy.constant;
}
/**
 *  @fn	Types SemanticNodeCast::getType(void)
 *
 *  @brief	Gets the type this instance of ValueType represents.
 *
 *  @author	Nikola Novak.
 *  @date	6/15/2009.
 *
 *  @return	The type.
 */
ValueType::Types ValueType::getType(void) const {
	return type;
}
/**
 *  @fn	Types ValueType::getType(std::string typeName) const
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @param	typeName	.
 *
 *  @return	.
 */
ValueType::Types ValueType::getType(std::string typeName) {
	if (typeName == "int") return Int;
	if (typeName == "float") return Float;
	if (typeName == "bool") return Bool;
	if (typeName == "state") return State;
	if (typeName == "time") return Time;
	if (typeName == "void") return Void;
	if (typeName == "Facility") return Facility;
	if (typeName == "Storage") return Storage;
	if (typeName == "Queue") return Queue;
	if (typeName == "ADTable") return ADTable;
	if (typeName == "Group") return Group;
	if (typeName == "OutputStream") return OutputStream;
	return UserDefined;
}
/**
 *  @fn	void ValueType::setType(const SyntaxTreeNode *variableTypeNode, std::string userTypeName)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @param	variableTypeNode	.
 *  @param	userTypeName		.
	*  @param dimensions .
 */
void ValueType::setType(const SyntaxTreeNode *variableTypeNode, int nDimensions) {
	dimensionality = nDimensions;
	switch (variableTypeNode->Production) {
		case Gr_DataType__ADTable:
			type = ADTable;
			typeName = "ADTable";
			break;
		case Gr_DataType__bool:
			type = Bool;
			typeName = "bool";
			break;
		case Gr_DataType__Facility:
			type = Facility;
			typeName = "Facility";
			break;
		case Gr_DataType__float:
			type = Float;
			typeName = "float";
			break;
		case Gr_DataType__Group:
			type = Group;
			typeName = "Group";
			break;
		case Gr_DataType__int:
			type = Int;
			typeName = "int";
			break;
		case Gr_DataType__Name:
			type = UserDefined;
			typeName = flattenTypeName(*variableTypeNode);
			break;
		case Gr_DataType__Name_TemplateUse:
			type = UserDefinedTemplate;
			typeName = flattenTypeName(*variableTypeNode);
			setTemplate(flattenTemplateIdentifiers(*variableTypeNode->Nodes->GetData(1)->Nodes->GetData(1)));
			break;
		case Gr_DataType__OutputStream:
			type = OutputStream;
			typeName = "OutputStream";
			break;
		case Gr_DataType__Queue:
			type = Queue;
			typeName = "Queue";
			break;
		case Gr_DataType__state:
			type = State;
			typeName = "state";
			break;
		case Gr_DataType__Storage:
			type = Storage;
			typeName = "Storage";
			break;
		case Gr_DataType__time:
			type = Time;
			typeName = "time";
			break;
		case Gr_DataType__void:
			type = Void;
			typeName = "void";
			break;
	}
}
/**
 *  @fn	void ValueType::setType(Types type, int dimensions)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @param	type		.
 *  @param	dimensions	.
 */
void ValueType::setType(Types type, int nDimensions) {
	this->type = type;
	this->dimensionality = nDimensions;
	setTypeName(type);
}
/**
 *  @fn	void ValueType::setTemplate(const SyntaxTreeNode *templateNode)
 *
 *  @brief	Sets the template for this ValueType.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @param	templateNode	Syntax node at the root of the template.
 */
void ValueType::setTemplate(std::vector<std::string> names) {
	myTemplate.clear();
	for (std::vector<std::string>::iterator i = names.begin(); i != names.end(); ++i) {
		ValueType *nxt = new ValueType(0);
		nxt->type = getType((*i));
		nxt->typeName = *i;
		myTemplate.push_back(nxt);
	}
}
/**
 *  @fn	std::string ValueType::getTypeDebugString(void)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	.
 */
std::string ValueType::getTypeDebugString(void) {
	std::ostringstream res;
	res << typeName;
	if (hasTemplate())
	{
		res  << "<";
		for (std::vector<ValueType *>::iterator i = myTemplate.begin(); i != myTemplate.end();) {
			res << (*i)->typeName;
			if ((++i) != myTemplate.end())	res << ", ";
		}
		res << ">";
	}
	for (int x = 0; x < dimensionality; ++x) {
		res << "[";
		if (dimensions.size() >= x + 1) res << dimensions[x];
		res << "]";
	}
	return res.str();
}
/**
 *  @fn	int ValueType::getID(void) const
 *
 *  @brief	Gets the ID of this ValueType instance.
 *
 *  @author	Nikola Novak.
 *  @date	6/16/2009.
 *
 *  @return	ID number.
 */
int ValueType::getID(void) const {
 return id;
}

/**
 *  @fn	void ValueType::setID(int newID)
 *
 *  @brief	Sets the ID of this ValueType instance. (DEPRECATED)
 *
 *  @author	Nikola Novak.
 *  @date	6/16/2009.
 *
 *  @param	newID	ID number to set.
 */
void ValueType::setID(int newID) {
	id = newID;
}
/**
 *  @fn	bool ValueType::operator==(const ValueType &type1, const ValueType &type2)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @param	type1	.
 *  @param	type2	.
 *
 *  @return	.
 */
bool ValueType::operator==(const ValueType &type) const {
	if (type.id == this->id) return true;
	if (type.type == this->type) {
		if (this->typeName != type.typeName) return false;
		if (this->isArray() && !type.isArray()) return false;
		else if (this->isArray()) {
			if (this->dimensionality != type.dimensionality) return false;
			if (this->evaluated && type.evaluated) {
				for (int x = 0; x < dimensions.size(); ++x) {
					if (this->dimensions[x] != type.dimensions[x]) return false;
				}
			}
		}
		if (this->type == UserDefinedTemplate && !compareTemplates(type)) return false;
	} else return false;
	return true;
}
/**
 *  @fn	bool ValueType::operator!=(const ValueType &type) const
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @param	type	.
 *
 *  @return	.
 */
bool ValueType::operator!=(const ValueType &type) const {
	return !operator==(type);
}

/**
 *  @fn	bool ValueType::isArray(void)
 *
 *  @brief	Checks whether this instance of ValueType is an array.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True if array, false otherwise.
 */
bool ValueType::isArray(void) const {
	return dimensions.size() > 0; // dimensionality > 0;
}
/**
 *  @fn	bool ValueType::isEvaluated(void) const
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/22/2009.
 *
 *  @return	.
 */
bool ValueType::isEvaluated(void) const {
	return evaluated;
}
/**
 *  @fn	int ValueType::getDimensions(void) const
 *
 *  @brief	Gets the dimensionality of this array, 0 if not array.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	Dimensionality.
 */
int ValueType::getDimensions(void) const {
	return dimensions.size();
}
/**
 *  @fn	int ValueType::getTypeName(void) const
 *
 *  @brief	Gets the type name.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	Type name.
 */
std::string ValueType::getTypeName(void) const {
	return typeName;
}
/**
 *  @fn	void ValueType::setTypeName(Types type)
 *
 *  @brief	Sets the type name.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @param	type	Type.
 */
void ValueType::setTypeName(Types type) {
	switch(type) {
		case UserDefinedTemplate:
		case UserDefined:
			// We don't know the name, it must be passed using setType(std::string, int);
			// this should never happen
			return;
		case Int: typeName = "int"; break;
		case Float: typeName = "float"; break;
		case Bool: typeName = "bool"; break;
		case State: typeName = "state"; break;
		case Time: typeName = "time"; break;
		case Void: typeName = "void"; break;
		case Facility: typeName = "Facility"; break;
		case Storage: typeName = "Storage"; break;
		case Queue: typeName = "Queue"; break;
		case ADTable: typeName = "ADTable"; break;
		case Group: typeName = "Group"; break;
		case OutputStream: typeName = "OutputStream"; break;
		default: /* Cannot happen. */ break;
	}
}
/**
 *  @fn	bool ValueType::compareTemplates(const ValueType &type) const
 *
 *  @brief	Compares templates of this ValueType and another ValueType.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @param	type	Another ValueType.
 *
 *  @return	True if templates are the same, false otherwise.
 */
bool ValueType::compareTemplates(const ValueType &type) const {
	if (myTemplate.size() != type.myTemplate.size()) return false;
	int x = 0;
	for (std::vector<ValueType *>::const_iterator i = myTemplate.begin(); i != myTemplate.end(); ++i, ++x) {
		if (*(*i) != *type.myTemplate[x]) return false;
	}
	return true;
}
/**
 *  @fn	bool ValueType::isInt(void)
 *
 *  @brief	Checks whether this ValueType is int.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isInt(void) const {
	return type == Int;
}
/**
 *  @fn	bool ValueType::isFloat(void)
 *
 *  @brief	Checks whether this ValueType is float.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isFloat(void) const {
	return type == Float;
}
/**
 *  @fn	bool ValueType::isBool(void)
 *
 *  @brief	Checks whether this ValueType is bool.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isBool(void) const {
	return type == Bool;
}
/**
 *  @fn	bool ValueType::isState(void)
 *
 *  @brief	Checks whether this ValueType is state.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isState(void) const {
	return type == State;
}
/**
 *  @fn	bool ValueType::isTime(void)
 *
 *  @brief	Checks whether this ValueType is time.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isTime(void) const {
	return type == Time;
}
/**
 *  @fn	bool ValueType::isVoid(void)
 *
 *  @brief	Checks whether this ValueType is void.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isVoid(void) const {
	return type == Void;
}
/**
 *  @fn	bool ValueType::isFacility(void)
 *
 *  @brief	Checks whether this ValueType is Facility.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isFacility(void) const {
	return type == Facility;
}
/**
 *  @fn	bool ValueType::isStorage(void)
 *
 *  @brief	Checks whether this ValueType is Storage.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isStorage(void) const {
	return type == Storage;
}
/**
 *  @fn	bool ValueType::isQueue(void)
 *
 *  @brief	Checks whether this ValueType is Queue.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isQueue(void) const {
	return type == Queue;
}
/**
 *  @fn	bool ValueType::isADTable(void)
 *
 *  @brief	Checks whether this ValueType is ADTable.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isADTable(void) const {
	return type == ADTable;
}
/**
 *  @fn	bool ValueType::isGroup(void)
 *
 *  @brief	Checks whether this ValueType is Group.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isGroup(void) const {
	return type == Group;
}
/**
 *  @fn	bool ValueType::isOutputStream(void)
 *
 *  @brief	Checks whether this ValueType is OutputStream.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isOutputStream(void) const {
	return type == OutputStream;
}
/**
 *  @fn	bool ValueType::isUserDefinedType(void)
 *
 *  @brief	Checks whether this ValueType is a user defined type.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::isUserDefinedType(void) const {
	return type == UserDefined || type == UserDefinedTemplate;
}
/**
 *  @fn	bool ValueType::hasTemplate(void)
 *
 *  @brief	Checks whether this ValueType has a template.
 *
 *  @author	Nikola Novak.
 *  @date	6/19/2009.
 *
 *  @return	True for yes, false for no.
 */
bool ValueType::hasTemplate(void) const {
	return myTemplate.size() > 0;
}
/**
 *  @fn	bool ValueType::isConstant(void) const
 *
 *  @brief	Query if this object is constant.
 *
 *  @author	Nikola Novak
 *  @date	6/19/2009
 *
 *  @return	true if constant, false if not.
 */
bool ValueType::isConstant(void) const {
	return constant;
}
/**
 *  @fn	void ValueType::makeConstant(void)
 *
 *  @brief	Makes this value type constant.
 *
 *  @author	Nikola Novak
 *  @date	6/19/2009
 */
void ValueType::makeConstant(void) {
	constant = true;
}
